package snafu.implementation.actions.walk.forward;

import java.util.List;

import snafu.framework.actions.IntentionItself;
import snafu.framework.actions.IntentionView;
import snafu.framework.agents.AgentState;
import snafu.framework.objects.WorldObject;
import snafu.framework.view.Access;
import snafu.framework.worlds.Position;
import snafu.framework.worlds.Tile;
import snafu.framework.worlds.WorldMap;
import snafu.implementation.states.literals.direction.DirectionLiteral;
import snafu.implementation.states.literals.position.PositionLiteral;
import snafu.implementation.states.literals.walk.WalkableLiteral;

public class WalkForwardIntentionItself extends IntentionItself<WalkForwardAction> implements
		WalkForwardIntention {

	public WalkForwardIntentionItself(Access privacy) {
		super(privacy);
	}

	@Override
	public WalkForwardAction createAction(List<WorldObject> targets) {
		return new WalkForwardAction(targets, this);
	}

	@Override
	public IntentionView<WalkForwardAction> createView(Access access) {
		return new WalkForwardIntentionView(access, this);
	}

	@Override
	protected boolean checkApplicability(WorldMap perception, AgentState agent,
			List<WorldObject> targets) {
		
		// get the current position and direction of the agent
		Position position = agent.getLiteral(PositionLiteral.class);
		Integer direction = agent.getLiteral(DirectionLiteral.class, 0);
		
		// get the tile in front of the agent
		Tile front = perception.getFrontTile(position, direction);
		
		// there is no front
		if (front == null) {
			return false;
		}
		
		switch (targets.size()) {
		// no target specified => look for on in front
		case 0:
			// look if there's an object he can walk on
			for (WorldObject object : front.getWorldObjects()) {
				if (object.getState().getLiteral(WalkableLiteral.class, false)) {
					return true;
				}
			}
			// no object found
			break;
		// a concrete target specified
		case 1:
			// get the only target
			WorldObject target = targets.get(0);
			// look if the target is in front of the agent and walkable
			for (WorldObject object : front.getWorldObjects()) {
				if (object.equals(target) && target.getState().getLiteral(WalkableLiteral.class, false)) {
					return true;
				}
			}
			// object is not in front of the agent or not walkable
			break;
		}
		
		// not applicable
		return false;
	}

}
